﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using WgFrame.Net.Peer;

namespace WgFrame.Net.Socket
{
    public class HttpSocket : IWgSocket
    {
        public HttpSocket(PeerBase peerBase) : base(peerBase)
        {
        }

        private bool isInit { get { return string.IsNullOrEmpty(peerBase.ConnectionId); } }

        public override bool Connect()
        {
            if (!base.Connect())
            {
                return false;
            }
            State = WgSocketState.Connected;
            ServerIpAddress = peerBase.ServerAddress;
            peerBase.OnConnect();
            return true;
        }

        public override bool Disconnect()
        {
            if (isInit)
            {
                return true;
            }

            if (ReportDebugOfLevel(DebugLevel.INFO))
            {
                EnqueueDebugReturn(DebugLevel.INFO, "HttpSocket.Disconnect()");
            }

            byte[] buf = new byte[1];
            buf[0] = 1;
            State = WgSocketState.Disconnecting;
            Send(buf,  buf.Length);
            State = WgSocketState.Disconnected;
            return true;
        }

        public override WgSocketError Send(byte[] data, int length)
        {
            byte[] res = new byte[length];
            Buffer.BlockCopy(data, 0, res, 0, length);

            HttpParameters httpSendParameters = new HttpParameters()
            {
                Url = ServerIpAddress + (isInit ? "?init" : "?pid=" + peerBase.ConnectionId),
                Data = res,
                TimeOut = peerBase.DisconnectTimeout,
                OnSucc = (d) =>
                {
                    peerBase.ReceiveIncomingCommands(d, d.Length);
                },
                OnError = (msg) =>
                {
                    if (ReportDebugOfLevel(DebugLevel.ERROR))
                    {
                        EnqueueDebugReturn(DebugLevel.ERROR, msg);
                    }

                    if (isInit)
                    {
                        HandleException(StatusCode.ExceptionOnConnect);
                    }
                    else
                    {
                        HandleException(StatusCode.SendError);
                    }
                }
            };
            HttpHandler.Instance.SendData(httpSendParameters);
            return WgSocketError.Success;
        }
    }

    struct HttpParameters
    {
        public string Url;
        public byte[] Data;
        public Action<byte[]> OnSucc;
        public Action<string> OnError;
        public int TimeOut;
    }

    class HttpHandler : MonoBehaviour
    {
        private static HttpHandler instance;

        public static HttpHandler Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = FindObjectOfType<HttpHandler>();
                    if (instance == null)
                    {
                        GameObject gameObject = new GameObject("HttpHandler");
                        instance = gameObject.AddComponent<HttpHandler>();
                    }
                }
                return instance;
            }
        }

        public void SendData(HttpParameters parameters)
        {
            StartCoroutine(Post(parameters));
        }

        private IEnumerator Post(HttpParameters parameters)
        {
            UnityWebRequest webRequest = new UnityWebRequest(parameters.Url, "POST");
            webRequest.timeout = parameters.TimeOut;
            webRequest.uploadHandler = new UploadHandlerRaw(parameters.Data);
            webRequest.uploadHandler.contentType = "text/plain";
            webRequest.downloadHandler = new DownloadHandlerBuffer();

            yield return webRequest.SendWebRequest();

            if (webRequest.isHttpError || webRequest.isNetworkError)
            {
                if (parameters.OnError != null)
                {
                    parameters.OnError(webRequest.error);
                }
            }
            else
            {
                if (parameters.OnSucc != null)
                {
                    parameters.OnSucc(webRequest.downloadHandler.data);
                }
            }
        }
    }
}
